package com.paper.tiger.easy.rpc.s.client.client;

import com.paper.tiger.easy.rpc.core.GeneralHandleData;
import com.paper.tiger.easy.rpc.core.RegisterServerMesage;
import com.paper.tiger.easy.rpc.core.ServerType;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * [简要描述]:
 * [详细描述]:
 *
 * @author ZouHaiBo
 * @version 1.0, 2021/5/31 10:40
 * @since JDK 1.8
 */
public class RegisterService
{

    private static Executor executor = Executors.newSingleThreadExecutor();

    /**
     * 单个注册
     */
    public static void registerService(RegisterServerMesage mesage)
    {

        List<RegisterServerMesage> messages = new ArrayList<>();
        messages.add(mesage);
        GeneralHandleData data = new GeneralHandleData();
        data.setList(messages);
        data.setType(ServerType.REGISTER_REQUEST.getCode());
        try
        {
            registerServices(messages);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

    }

    /**
     * 批量注册
     *
     * @param list
     */
    public static void registerServices(List<RegisterServerMesage> list) throws IOException
    {

        GeneralHandleData data = new GeneralHandleData();
        data.setList(list);
        data.setType(ServerType.REGISTER_REQUEST.getCode());

        executor.execute(new RegisterSocket(data));

        // 把服务加入到容器

        for (RegisterServerMesage mesage : list)
        {
            SelectService.map.put(mesage.getInterfaceClass(),mesage);
        }

    }

    public static void startServer(int port)
    {
        ServerSocket serverSocket = null;
        try
        {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(port));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        while (true)
        {
            try
            {
                Socket accept = serverSocket.accept();
                executor.execute(new ServiceSocket(accept));
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }

        }
    }

    private static class ServiceSocket implements Runnable
    {

        private Socket socket;

        public ServiceSocket(Socket socket)
        {
            this.socket = socket;
        }

        @Override
        public void run()
        {
            ObjectInputStream inputStream = null;
            ObjectOutputStream outputStream = null;
            try
            {
                inputStream = new ObjectInputStream(socket.getInputStream());
                outputStream = new ObjectOutputStream(socket.getOutputStream());

                Invoke data = (Invoke) inputStream.readObject();

                // 完成对具体方法的调用
                String interfaceClassName = data.getInterfaceClassName();
                RegisterServerMesage mesage = SelectService.map.get(interfaceClassName);
                Class<?> clazz = Class.forName(mesage.getImplClass());
                Method method = clazz.getMethod(data.getMethod(), data.getParamsTypes());
                Object invoke = method.invoke(clazz.newInstance(), data.getArgs());

                outputStream.writeObject(invoke);
                outputStream.flush();

                System.out.println(data);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }

            finally
            {
                try
                {
                    socket.close();
                    outputStream.close();
                    inputStream.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }

        }
    }

    private static class RegisterSocket implements Runnable
    {

        private GeneralHandleData data;

        public RegisterSocket(GeneralHandleData data)
        {
            this.data = data;
        }

        @Override
        public void run()
        {
            Socket socket = null;
            ObjectInputStream inputStream = null;
            ObjectOutputStream outputStream = null;
            try
            {
                socket = new Socket();
                socket.connect(new InetSocketAddress(RegisterCenterConst.host, RegisterCenterConst.center_port));

                outputStream = new ObjectOutputStream(socket.getOutputStream());
                inputStream = new ObjectInputStream(socket.getInputStream());

                outputStream.writeObject(data);
                outputStream.flush();
                GeneralHandleData data = (GeneralHandleData) inputStream.readObject();

                System.out.println(data);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
            finally
            {
                try
                {
                    socket.close();
                    outputStream.close();
                    inputStream.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }

        }
    }

}
